import java.util.Random;
import java.util.LinkedList;
import java.util.Queue;
import java.awt.Point;

public class Minesweeper {

    private byte[][] grid; 
    private byte[][] gridStatus;
    private Point[] minesSite;
    private int uncleanCount;

    public static final byte CLEANED = Byte.MAX_VALUE;
    public static final byte UNCLEAN = Byte.MAX_VALUE - 1;
    public static final byte DOUBT   = Byte.MAX_VALUE - 2;
    public static final byte DANGER  = Byte.MAX_VALUE - 3;


    /**
     * 设置网格数量和地雷数量并初始化游戏
     * @param w
     * @param h
     * @param mineCount
     */
    public void StartGame(int w, int h, int mineCount){

        if(w * h <= mineCount)
            throw new UnsupportedOperationException("这么多地雷，还扫个屁");

        // 初始化成员
        grid = new byte[h][w];
        gridStatus = new byte[h][w];
        uncleanCount = h * w;
        minesSite = new Point[mineCount];
        for(int i = 0; i != h; ++i)
            for(int j = 0; j != w; ++j)
                gridStatus[i][j] = UNCLEAN;

        var rand = new Random();
        for(int i = 0; i != mineCount; ++i){

            // 随机生成一个不处在小于mineCount的位置
            int index = rand.nextInt(grid.length * grid[0].length - mineCount) + mineCount;
            int row = index / grid[0].length;
            int col = index % grid[0].length;
            
            // 如果该位置已经有地雷了，则将地雷放置在i处
            if(grid[row][col] < 0){
                row = i / grid[0].length;
                col = i % grid[0].length;
            }
            
            // 放置地雷
            grid[row][col] = Byte.MIN_VALUE;
            minesSite[i] = new Point(row, col);
            
            // 更新地雷周围的8个格子
            for(int offsetRow = - 1; offsetRow <= 1; ++offsetRow)
                for(int offsetCol = -1; offsetCol <= 1; ++offsetCol)
                    if(row + offsetRow >= 0 && row + offsetRow < grid.length && 
                       col + offsetCol >= 0 && col + offsetCol < grid[0].length)
                       ++grid[row + offsetRow][col + offsetCol];
        }
    }

    /**
     * 获取row,col处的内容
     * @param row
     * @param col
     * @return 返回值<0表示地雷，0<=返回<9表示该位置周围有多少颗地雷， 返回UNCLEAN，DOUBT，DANGER其中一个表示该位置的状态
     */
    public byte Grid(int row, int col){
        return gridStatus[row][col] == CLEANED ? grid[row][col] : gridStatus[row][col];
    }

    /***
     * 清理row,col处的网格，同时清理周围无意义的网格
     * @param row
     * @param col
     * @return 该位置有地雷返回-1， 清理成功返回0，找到了所有地雷返回1
     */
    public byte Clear(int row, int col){

        if(grid[row][col] < 0){
            for (var pos : minesSite) {
                gridStatus[pos.x][pos.y] = CLEANED;
            }
            uncleanCount -= minesSite.length;
            return -1;
        }

        Queue<Point> queue = new LinkedList<Point>();
        queue.offer(new Point(row, col));
        while(!queue.isEmpty()){
            var pos = queue.poll();
            if(gridStatus[pos.x][pos.y] == CLEANED)
                continue;

            gridStatus[pos.x][pos.y] = CLEANED;
            --uncleanCount;
            
            if(grid[pos.x][pos.y] > 0)
                continue;

            for(int offsetRow = - 1; offsetRow <= 1; ++offsetRow)
            for(int offsetCol = -1; offsetCol <= 1; ++offsetCol)
                if(pos.x + offsetRow >= 0 && pos.x + offsetRow < grid.length && 
                    pos.y + offsetCol >= 0 && pos.y + offsetCol < grid[0].length && (offsetCol != 0 || offsetRow != 0))
                    queue.offer(new Point(pos.x + offsetRow, pos.y + offsetCol));
        }

        return (byte)(uncleanCount == minesSite.length ? 1 : 0);
    }

    /**
     * @return 网格高度
     */
    public int H(){
        return grid.length;
    }

    /**
     * @return 网格宽度
     */
    public int W(){
        return grid[0].length;
    }

    /**
     * 更改row,col处的标记，只有row,col处是未清理的才可以更改标记
     * @param row
     * @param col
     * @param mark 要打的标记 可能的值：UNCLEAN, DANGER, DOUBT
     */
    public void Mark(int row, int col, byte mark){
        gridStatus[row][col] = gridStatus[row][col] != CLEANED ? mark : gridStatus[row][col];
    }
}
